import { TRPCError } from "@trpc/server";
import { isDefined } from "@typebot.io/lib/utils";
import prisma from "@typebot.io/prisma";
import { resultWithAnswersSchema } from "@typebot.io/results/schemas/results";
import { isReadTypebotForbidden } from "@typebot.io/typebot/helpers/isReadTypebotForbidden";
import { z } from "@typebot.io/zod";
import {
  defaultTimeFilter,
  timeFilterValues,
} from "@/features/analytics/constants";
import {
  parseFromDateFromTimeFilter,
  parseToDateFromTimeFilter,
} from "@/features/analytics/helpers/parseDateFromTimeFilter";
import { authenticatedProcedure } from "@/helpers/server/trpc";

const MAX_LIMIT = 500;

export const getResults = authenticatedProcedure
  .meta({
    openapi: {
      method: "GET",
      path: "/v1/typebots/{typebotId}/results",
      protect: true,
      summary: "List results ordered by descending creation date",
      tags: ["Results"],
    },
  })
  .input(
    z.object({
      typebotId: z
        .string()
        .describe(
          "[Where to find my bot's ID?](../how-to#how-to-find-my-typebotid)",
        ),
      limit: z.coerce.number().min(1).max(MAX_LIMIT).default(50),
      cursor: z.coerce.number().optional(),
      timeFilter: z.enum(timeFilterValues).default(defaultTimeFilter),
      timeZone: z.string().optional(),
    }),
  )
  .output(
    z.object({
      results: z.array(resultWithAnswersSchema),
      nextCursor: z.number().nullish(),
    }),
  )
  .query(async ({ input, ctx: { user } }) => {
    const limit = Number(input.limit);
    if (limit < 1 || limit > MAX_LIMIT)
      throw new TRPCError({
        code: "BAD_REQUEST",
        message: `limit must be between 1 and ${MAX_LIMIT}`,
      });
    const { cursor } = input;
    const typebot = await prisma.typebot.findUnique({
      where: {
        id: input.typebotId,
      },
      select: {
        id: true,
        groups: true,
        collaborators: {
          select: {
            userId: true,
            type: true,
          },
        },
        workspace: {
          select: {
            isSuspended: true,
            isPastDue: true,
            members: {
              select: {
                userId: true,
              },
            },
          },
        },
      },
    });
    if (!typebot || (await isReadTypebotForbidden(typebot, user)))
      throw new TRPCError({ code: "NOT_FOUND", message: "Typebot not found" });

    const fromDate = parseFromDateFromTimeFilter(
      input.timeFilter,
      input.timeZone,
    );
    const toDate = parseToDateFromTimeFilter(input.timeFilter, input.timeZone);

    const results = await prisma.result.findMany({
      take: limit + 1,
      skip: cursor,
      where: {
        typebotId: typebot.id,
        hasStarted: true,
        isArchived: false,
        createdAt: fromDate
          ? {
              gte: fromDate,
              lte: toDate ?? undefined,
            }
          : undefined,
      },
      orderBy: {
        createdAt: "desc",
      },
      include: {
        answers: {
          select: {
            blockId: true,
            content: true,
            createdAt: true,
          },
        },
        answersV2: {
          select: {
            blockId: true,
            content: true,
            createdAt: true,
          },
        },
      },
    });

    let nextCursor: number | undefined;
    if (results.length > limit && isDefined(cursor)) {
      nextCursor = cursor + limit;
    }

    return {
      results: z.array(resultWithAnswersSchema).parse(
        results.map((r) => ({
          ...r,
          answers: r.answersV2
            .concat(r.answers)
            .sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()),
        })),
      ),
      nextCursor,
    };
  });
